package org.zavgame.ejb;

import java.util.concurrent.atomic.AtomicReference;

import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;

/**
 * Statistic registry singleton class.
 * Uses for collect statistic data and print it for the log.
 */
public class StatisticRegistry
{

   /**
    * Flush the log every described seconds.
    */
   protected static final int LOG_EVERY_SECONDS = 60;
   
   /**
    * Log category name.
    */
   protected static final String STAT_LOG_CATEGORY_NAME = "ZAVGAME-stat";

   private static AtomicReference<StatisticRegistry> stat = new AtomicReference<StatisticRegistry>();

   /**
    * Requests number.
    */
   private long num;

   /**
    * Better time requests.
    */
   private long better;

   /**
    * Worse time requests.
    */
   private long worse;

   /**
    * All time request.
    */
   private long count;

   /**
    * Default constructor.
    */
   private StatisticRegistry()
   {
   }

   /**
    * Add a request time. 
    * @param time
    */
   synchronized public void add(long time)
   {
      num++;
      if (num == 1 || time < better)
      {
         better = time;
      }
      if (time > worse)
      {
         worse = time;
      }
      count += time;
   }

   /**
    * Getting the log.
    * 
    * @return log line
    */
   protected String getLog()
   {
      StringBuilder sb = new StringBuilder();
      sb.append("num = ").append(num);
      sb.append(", better = ").append(better);
      sb.append(", worse = ").append(worse);
      sb.append(", avg = ").append(num == 0 ? num : count / num);
      return sb.toString();
   }

   /**
    * Clean the log.
    */
   protected void clean()
   {
      num = 0;
      better = 0;
      worse = 0;
      count = 0;
   }

   /**
    * Get StatisticRegistry singleton instance.
    * @return
    */
   public static StatisticRegistry getInstance()
   {
      StatisticRegistry st = stat.get();
      if (st != null)
      {
         return st;
      }
      synchronized (stat)
      {
         st = stat.get();
         if (st != null)
         {
            return st;
         }
         // if there is no create one and single
         st = new StatisticRegistry();
         stat.compareAndSet(null, st);
      }
      return stat.get();
   }

   /**
    * Create and run the logging thread.
    */
   public void runThread()
   {
      Thread t = new Thread(new Runnable()
      {
         
         private Logger LOG = Logger.getInstance(LogCategory.OPENEJB.createChild(STAT_LOG_CATEGORY_NAME),
            StatisticRegistry.class.getName());

         @Override
         public void run()
         {
            while (true)
            {
               // write log every LOG_EVERY_SECONDS seconds
               StatisticRegistry instance = StatisticRegistry.getInstance();
               LOG.info(instance.getLog());
               instance.clean();
               try
               {
                  Thread.currentThread().sleep(LOG_EVERY_SECONDS * 1000);
               }
               catch (InterruptedException e)
               {
                  e.printStackTrace();
               }
            }
         }
      });
      t.start();
   }

}
